package individual.ircon.bilibili.network;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

public class CommentHttpApi {

    /// ==============================
    /// === Private Static Function ===
    /// ==============================

    /**
     * 获取相应的JSON对象。
     *
     * @param url 链接
     * @return JSON对象
     * @throws IOException          IO异常。
     * @throws InterruptedException 中断异常。
     */
    private static JSONObject requestUrl(String url) throws IOException, InterruptedException {
        HttpClient client = HttpClient
                .newBuilder().connectTimeout(Duration.ofSeconds(3)).build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url)).timeout(Duration.ofSeconds(3)).GET().build();

        HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
        return JSON.parseObject(res.body());
    }


    /**
     * 获取评论的评论的API。
     *
     * @param pn   第几页，从1开始。
     * @param ps   一页有几个评论
     * @param oid  视频的oid
     * @param root 根评论的id
     * @return 网址URL
     */
    private static String getCommentApiUrlUnderRoot(int pn, int ps, long oid, long root) { // 先留着，以后想做了再做。
        return String.format(
                "https://api.bilibili.com/x/v2/reply/reply?jsonp=jsonp&pn=%d&type=1&oid=%d&ps=%d&root=%d",
                pn, oid, ps, root
        );
    }

    /**
     * 视频的评论。
     *
     * @param pn  页数，从1开始。
     * @param oid 视频的oid
     * @return 网址
     */
    private static String getRootCommentApiUrl(int pn, long oid) {
        return String.format("https://api.bilibili.com/x/v2/reply?&jsonp=jsonp&pn=%d&type=1&oid=%d&sort=2", pn, oid);
    }

    /**
     * 视频信息的。
     *
     * @param bv bv号
     * @return 网址
     */
    private static String getVideoInfoApiUrl(String bv) {
        return String.format("http://api.bilibili.com/x/web-interface/view?bvid=%s", bv);
    }

    /// ==============================
    /// === Public Static Function ===
    /// ==============================

    /**
     * 获取视频信息。如果BV号错误，返回NULL。
     *
     * @param bv 视频的bv，如果BV号错误，返回NULL。
     * @return 视频信息对象
     * @throws IOException 如果网络异常。
     */
    public static VideoInfo getVideoInof(String bv) throws IOException {
        JSONObject ob = null;
        try {
            ob = requestUrl(getVideoInfoApiUrl(bv));
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            throw new IOException("获取视频信息失败。", e);
        }

        if(ob.getIntValue("code") != 0) {
            return null;
        }
        VideoInfo info = new VideoInfo();
        info.Aid = ob.getJSONObject("data").getLongValue("aid");
        info.Title = ob.getJSONObject("data").getString("title");
        info.UpName = ob.getJSONObject("data").getJSONObject("owner").getString("name");
        info.Desc = ob.getJSONObject("data").getString("desc");
        return info;
    }


    /**
     * 获取视频下面所有评论。不包含评论的评论。
     * @param info 视频信息对象
     * @return 所有的评论
     * @throws IOException 如果网络出现错误。
     */
    public static List<Comment> getRootComment(VideoInfo info) throws IOException {
        ArrayList<Comment> list = new ArrayList<>();
        int n = 1, end = 0;

        try {

            do {
                var js = requestUrl(getRootCommentApiUrl(n, info.Aid));
                js = js.getJSONObject("data");
                if (n == 1) {
                    int all = js.getJSONObject("page").getIntValue("count");
                    int size = js.getJSONObject("page").getIntValue("size");
                    end = (all / size) + (all % size == 0 ? 0 : 1);

                }
                JSONArray array = js.getJSONArray("replies");
                for (int i = 0; i < array.size(); ++i) {
                    var v = array.getJSONObject(i);
                    Comment com = new Comment(
                            v.getLongValue("rpid"),
                            v.getLongValue("mid"),
                            v.getJSONObject("member").getString("uname"),
                            v.getJSONObject("content").getString("message"));
                    list.add(com);
                }
            } while (n++ <= end);

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            throw new IOException("获取评论失败。", e);
        }
        return list;
    }

    /// ====================
    /// === Tool Classes ===
    /// ====================

    /**
     * 视频信息类。
     */
    public static class VideoInfo {
        public long Aid;
        public String Title;
        public String UpName;
        public String Desc;

        public VideoInfo() {
        }

        public VideoInfo(long aid, String title, String upName, String desc) {
            Aid = aid;
            Title = title;
            UpName = upName;
            Desc = desc;
        }

        @Override
        public String toString() {
            return "VideoInfo{" +
                    "Aid=" + Aid +
                    ", Title='" + Title + '\'' +
                    ", UpName='" + UpName + '\'' +
                    ", Desc='" + Desc + '\'' +
                    '}';
        }
    }

    /**
     * 评论类。
     */
    static public class Comment {
        public long Rpid;
        public long Mid;
        public String Name;
        public String Message;

        public Comment(long rpid, long mid, String name, String message) {
            this.Rpid = rpid;
            this.Mid = mid;
            this.Name = name;
            this.Message = message;
        }

        @Override
        public String toString() {
            return "Comment{" +
                    "Rpid=" + Rpid +
                    ", Mid=" + Mid +
                    ", Name='" + Name + '\'' +
                    ", Message='" + Message + '\'' +
                    '}';
        }
    }
}
